package org.jeecg.modules.flow.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.ProcessDefinitionQueryProperty;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.task.TaskInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.flow.query.FlowDefQuery;
import org.jeecg.modules.flow.service.IFlowDefService;
import org.jeecg.modules.flow.vo.FlowDefTaskVo;
import org.jeecg.modules.flow.vo.FlowDefVo;
import org.jeecg.modules.flow.vo.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class FlowDefServiceImpl implements IFlowDefService {


    @Autowired
    private RepositoryService repositoryService;

    @Override
    public BpmnModel getBpmnModel(String processDefinitionId) {
        BpmnModel bpmnModel = null;
        try {
            bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        } catch (Exception e) {
            log.error("获取BpmnModel失败,processDefinitionId：{},errMsg：{}", processDefinitionId, e.getMessage());
        }
        return bpmnModel;
    }

    /**
     * 获取流程节点
     *
     * @param processDefinitionId 流程定义ID
     * @param subProcessId        子流程ID
     * @return
     */
    public List<FlowElement> getFlowElements(String processDefinitionId, String subProcessId) {
        BpmnModel bpmnModel = getBpmnModel(processDefinitionId);
        List<FlowElement> flowElements = new ArrayList<>();
        if (bpmnModel == null) {
            return flowElements;
        }
        List<Process> processes = new ArrayList<>();
        if (StringUtils.isNotBlank(subProcessId)) {
            processes.add(bpmnModel.getProcessById(subProcessId));
        } else {
            processes = bpmnModel.getProcesses();
        }

        processes.forEach(process -> flowElements.addAll(process.getFlowElements()));

        return flowElements;
    }

    /**
     * 获取流程节点，加缓存
     *
     * @param processDefinitionId 流程定义ID
     * @return
     */
    public List<FlowElement> getFlowElements(String processDefinitionId) {
        return getFlowElements(processDefinitionId, null);
    }

    @Override
    @Cacheable(cacheNames = CacheConstant.FLOW_TASK_DEF_KEY, key = "#processDefinitionId+':'+#taskDefinitionKey")
    public String prevTaskDefKey(String processDefinitionId, String taskDefinitionKey) {
        List<FlowElement> flowElements = getFlowElements(processDefinitionId);
        if (flowElements == null) {
            return null;
        }
        List<FlowElement> userTasks = new ArrayList<>();
        for (FlowElement flowElement : flowElements) {
            if (flowElement instanceof UserTask) {
                userTasks.add(flowElement);
            }
        }
        for (int index = 0; index < userTasks.size(); index++) {
            if (taskDefinitionKey.equals(userTasks.get(index).getId())) {
                return index == 0 ? null : userTasks.get(index - 1).getId();
            }
        }
        return null;
    }

    @Override
    public List<FlowDefTaskVo> getProcessTaskNodes(String processId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processId).singleResult();
        if (processDefinition == null) {
            throw new JeecgBootException("流程不存在");
        }
        // 获取流程定义的所有节点信息
        List<FlowElement> processDefinitionNodes = getFlowElements(processId);

        List<FlowDefTaskVo> flowDefTaskVoList = new ArrayList<>();
        processDefinitionNodes.forEach(flowElement -> {
            FlowDefTaskVo flowDefTaskVo = new FlowDefTaskVo();
            // 筛选用户任务节点
            if (flowElement instanceof UserTask) {
                flowDefTaskVo.setProcessId(processId);
                flowDefTaskVo.setTaskId(flowElement.getId());
                flowDefTaskVo.setTaskName(flowElement.getName());
                flowDefTaskVo.setProcessName(processDefinition.getName());
                flowDefTaskVoList.add(flowDefTaskVo);
            }
        });
        return flowDefTaskVoList;
    }

    @Override
    public List<FlowDefVo> likeProcessName(String processName) {
        if (StringUtils.isBlank(processName)) {
            return null;
        }
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
                .processDefinitionNameLike(processName).list();
        List<FlowDefVo> list = getFlowDef(processDefinitions);

        // TODO 其实这一步不用后端处理 迁就。。。。。。
        list.forEach(flowDefVo -> {
            flowDefVo.setNameAndVersion(flowDefVo.getVersion() + "|" + flowDefVo.getName());
        });

        return list;
    }

    @Override
    public Page<FlowDefVo> queryList(FlowDefQuery query) {

        List<ProcessDefinition> definitions;
        ProcessDefinitionQuery dq = repositoryService.createProcessDefinitionQuery();
        if (StringUtils.isNotBlank(query.getDefName())) {
            dq = dq.processDefinitionNameLike(query.getDefName());
        }
        if (StringUtils.isNotBlank(query.getDefKey())) {
            dq = dq.processDefinitionKey(query.getDefKey());
        }
        if (StringUtils.isNotBlank(query.getOrderColumn())) {
            dq = dq.orderBy(ProcessDefinitionQueryProperty.findByName(query.getOrderColumn()));
        }
        definitions = dq.listPage(query.getFirstResult(), query.getMaxResults());
        List<FlowDefVo> list = getFlowDef(definitions);

        return new Page<>(list, dq.count());
    }


    /**
     * 加载定义信息
     *
     * @param definitions
     * @return
     */
    private List<FlowDefVo> getFlowDef(List<ProcessDefinition> definitions) {
        List<FlowDefVo> list = Lists.newArrayList();
        if (CollectionUtils.isEmpty(definitions)) {
            return list;
        }
        for (ProcessDefinition def : definitions) {
            FlowDefVo flowDefVo = FlowDefVo.builder()
                    .id(def.getId())
                    .deploymentId(def.getDeploymentId())
                    .key(def.getKey())
                    .name(def.getName())
                    .version(def.getVersion())
                    .suspensionState(def.isSuspended())
                    .build();
            list.add(flowDefVo);
        }
        return list;
    }
}
